package com.pawernode.message;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pawernode.vo.Orders;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * 消息接收者组件
 * 该类主要用于监听和处理来自RabbitMQ的消息
 */
@Component
@Slf4j
public class ReceiverMessage {

    /**
     * 用于序列化和反序列化JSON对象
     */
    @Resource
    private ObjectMapper objectMapper;

    /**
     * Redis模板，用于操作Redis数据库
     */
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 监听特定队列的消息并处理
     *
     * @param message 接收到的消息对象，包含消息的详细信息
     * @param channel RabbitMQ的通道，用于确认消息处理结果
     * @throws IOException 当消息体无法被正确反序列化时抛出的异常
     */
    @RabbitListener(queues = "queue.idempotent")
    public void receiveMsg(Message message, Channel channel) throws IOException {
        // 获取消息的唯一标词，类似于身份证
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        // 使用objectMapper把字节数组反序列化为对象
        Orders orders = objectMapper.readValue(message.getBody(), Orders.class);
        log.info("接收到的消息为：{}", orders);
        try {
            // 日志记录接收到的消息内容
            log.info("接收到的消息为：{}", orders.toString());
            // 如果不存在就在redis中存储订单id
            Boolean setResult = stringRedisTemplate.opsForValue().setIfAbsent("idempotent:" + orders.getOrderId(), orders.getOrderId());
            if (setResult) {
                // TODO 插入订单数据deng
                log.info("向数据库插入订单");
            }

            // 手动确认消息,false表示不批量确认,只有一个消息确认，true表示批量确认
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            // 当消息处理出现异常时，记录错误日志
            log.error("消息处理出现问题");
            try {
                // 拒绝消息，false表示不批量拒绝，true表示重新入队列
                channel.basicNack(deliveryTag, false, true);
            } catch (IOException ex) {
                // 如果消息拒绝过程中出现IO异常，则抛出运行时异常
                throw new RuntimeException(ex);
            }
            // 抛出运行时异常，表示消息处理失败
            throw new RuntimeException(e);
        }
    }
}
